//
// C++ Implementation: testLinkedList
//
// Description: 
//
//
// Author:  <>, (C) 2007
//
// Copyright: See COPYING file that comes with this distribution
//
//
#include <iostream>
#include "LinkedList.h"
#include "msg.h"
using namespace std;
using namespace msg; //from msg.h


//this function tests LinkedList's void remove(int index) and void clear() member functions
void remove_clear()
{
	LinkedList hop;
	Step("We want to test functions remove() and clear().",0);//0: restart counting&displaying step numbers
	Step("Creating a list with number 3,8,10,14.");
	hop.add(3); hop.add(8); hop.add(10); hop.add(14);
	hop.print();
	Pause(false);
	
	//testing remove(int index)
	Step("The first item of the list is then removed with remove(int index).\n This should remove the value 3.");
	hop.remove(0);
	Step("Calling print() should now give 8,10,14.");
	hop.print();
	Pause(false);
	Step("size() should return 3.");
	cout << hop.size() << endl;
	Pause();
	Step("Now we remove an item at the middle (10 at index 1).");
	hop.remove(1);
	Step("Calling print() should now give 8,14.");
	hop.print();
	Pause(false);
	Step("size() should return 2.");
	cout << hop.size() << endl;
	Pause();
	Step("We remove the last item 14.");
	hop.remove(1);
	Step("Calling print() should now give 8.");
	hop.print();
	Pause(false);
	Step("size() should return 1.");
	cout << hop.size() << endl;
	Pause();
	Step("We remove the remaining item (8 at index 0) which makes the list empty");
	hop.remove(0);
	Step("isEmpty() should return 1 (true).");
	cout << hop.isEmpty() << endl;
	Pause();
	Step("Now we try to remove an item at index 0.\nThis should give an error since the list is empty.");
	hop.remove(0);
	Pause(false);
	Step("We add a new value 23.");
	hop.add(23);
	Step("Calling print() should now give 23.");
	hop.print();
	Pause(false);
	Step("size() should return 1.");
	cout << hop.size() << endl;
	Pause();
	Step("We try to remove more elements with out of range indexes (-1 and 1).\nThis should give 2 warnings.");
	hop.remove(-1); hop.remove(1);
	Pause(false);
	Step("size() should return 1 (unchanged from before).");
	cout << hop.size() << endl;
	Pause();
	Step("We add a lot more elements to the list.");
	Step("The list becomes:");
	hop.add(10);hop.add(130);hop.add(12);hop.add(20);hop.add(18);hop.add(74);
	hop.print();
	Pause(false);
	
	//testing clear()
	Step("We empty the list with clear().");
	Step("The list becomes:");
	hop.clear();
	hop.print();
	Pause(false);
	Step("Now that the list empty, we call clear() again to see if the function is safe.");
	hop.clear();
	cout << "If you saw nothing or a debug message, clear() did its job correctly." << endl;
}

//this function tests LinkedList's void print(), int size() and bool isEmpyt() member functions
void print_size_isEmpty_add()
{
	//testing int size()
	LinkedList hop;
	Step("We want to test functions print(), size(), isEmpty() and add().",0);//0: restart counting&displaying step numbers
	Step("We have an empty LinkedList object.");
	Pause(false);
	Step("size() should return 0.");
	cout << hop.size() << endl;
	Pause(false);
	//testing bool isEmpty()
	Step("isEmpty() should return 1.");
	cout << hop.isEmpty() << endl;
	Pause(false);
	//testing print()
	Step("print() should display an empty list.");
	hop.print();
	Pause();
	Step("Now we use add(int value) to add items with values 3,8,10,14.");
	hop.add(3); hop.add(8); hop.add(10); hop.add(14);
	Step("Calling print() should now give 3,8,10,14.");
	hop.print();
	Pause();
	Step("The list's size is 4:");
	cout << hop.size() << endl;
	Pause(false);
	Step("With add(int index,int value) we add values 17, 18 and 19\nat indexes -1, 0 and after the last element at index 4+1=5.");
	Step("(you should see one error here for insertion at index -1)");
	hop.add(-1,17); hop.add(0,18); hop.add(5,19);
	Pause(false);
	Step("Calling print() should now give 18,3,8,10,14,19.");
	hop.print();
	Step("size() should return 6.");
	cout << hop.size() << endl;
	Pause();
	
}

void contains_get_search() //see if more functions can be tested together
{
	LinkedList hop;
	Step("We want to test functions contains(), get() and search().",0);//0: restart counting&displaying step numbers
	Step("We fill an empty list with the following values: 2, 1, 40, -2, 10, 2.");
	hop.add(2); hop.add(1); hop.add(40); hop.add(-2); hop.add(10); hop.add(2);
	hop.print();
	Pause();
	
	//testing of int get(int index) method
	Step("We get the value of elements at several indexes usint int get(int index).");
	Step("What is at index -3 (out of range) ? (errors, obtain -1)");
	cout << hop.get(-3) << endl;
	Pause(false);
	Step("What is at index 0 (first item) ? (2)");
	cout << hop.get(0) << endl;
	Pause(false);
	Step("What is at index 2 ? (40)");
	cout << hop.get(2) << endl;
	Pause(false);
	Step("What is at index 5 (last item) ? (2)");
	cout << hop.get(5) << endl;
	Pause(false);
	Step("What is at index 6 (out of range) ? (errors, obtain -1)");
	cout << hop.get(6) << endl;
	Pause();
	
	//testing of bool contains(int value) method
	Step("Now, we test if elements are in the list using bool contains(int value).");
	Step("Does the list contain 3 ? (no)");
	cout << boolToYesNo(hop.contains(3)) << endl;
	Pause(false);
	Step("Does the list contain -2 ? (yes)");
	cout << boolToYesNo(hop.contains(-2)) << endl;
	Pause();
	
	//testing of int search(int value) method
	Step("At last, we get the indexes of the first occurence of values using int search(int value).");
	Step("What's the index of 40 ? (2)");
	cout << hop.search(40) << endl;
	Pause(false);
	Step("What's the index of 18 (doesn't exist)? (-1)");
	cout << hop.search(18) << endl;
	
}

void add_all_remove_all()
{
	LinkedList a;
	LinkedList b;
	LinkedList c;
	
	b.add(-38);b.add(13);b.add(83);b.add(5);
	
	//showing to user first setup of two lists
	Step("We want to test functions addAll() and removeAll().",0);
	Step("We have an empty list A and a list B of 4 elements.");
	cout << "--A--" <<endl;
	a.print();
	cout << "--B--" <<endl;
	b.print();
	Pause();
	
	//removeAll with an input list empty of items (bulletproofing)
	Step("We try to remove elements of list B out of list A (this should produce nothing).");
	a.removeAll(&b);
	cout << "--A--" <<endl;
	a.print();
	cout << "--B--" <<endl;
	b.print();
	Pause();
	
	//addAll with the list that is used to add from being empty
	Step("We try to add all elements of A(empty list) into B(4 elements) to bulletproof addAll().");
	b.addAll(&a);
	Pause(false);
	Step("B should remain unchanged and still have its 4 elements: -38,13,83,5.");
	b.print();
	Pause();
	
	//setup list A by giving it some but not all of the elements of list B so that we have "mathematically" "A encompassed by B"
	Step("We add values 13 and 5 which exist in B into A.");
	a.add(b.get(1)); a.add(b.get(3));
	Step("Logically, B and A now have values 13 and 5 in common.");
	cout << "--A--" <<endl;
	a.print();
	cout << "--B--" <<endl;
	b.print();
	Pause();
	
	//clear and addAll used by operator=
	Step("Let list C be a backup copy of list A.\nnote: the assign operator used here, actually calls addAll() in background.");
	c = a;
	Step("C should be composed of 13, 5.");
	cout << "--C--" <<endl;
	c.print();
	
	//removeAll
	Pause();
	Step("Now let us remove all the elements within A that are common to B.");
	a.removeAll(&b);
	Pause(false);
	Step("A should now be empty:");
	a.print();
	Pause();
	
	//addAll
	Step("Let us remove all the elements within C that are common to B.");
	b.removeAll(&c);
	Pause(false);
	Step("B now has now 13 and 5 removed and should be made up of: -38, 83.");
	b.print();
	Pause(false);
	Step("C should be intact and still composed of: 13, 5.");
	c.print();
	Pause();
	
	//addAll once again but now with addAll(int index,Collection*):
	 //-at two out of range indexes before and after the dimensions...
	//-at the beginning, -in the middle, -at the end
	Step("Let us add all the elements of C back into B.");
	b.addAll(&c);
	Step("B should be -38, 83, 13, 5:");
	b.print();
	Pause();
	Step("Now we add using addAll(int index,Collection*) values of C: 13, 5\n* at -2 and 20: two out of range indexes\n* at the beginning (index:0)\n* at 4 in the middle of the list\n* at the very end with index size()");
	b.addAll(-2,&c);
	b.addAll(20,&c);
	b.addAll(0,&c);
	b.addAll(4,&c);
	b.addAll(b.size(),&c); //this is equivalent to b.addAll(&c) but we want make sure addAll(int,Collection*) behaves well with the index == lastIndex+1 which means appending to the end of the list
	Step("B should be 13, 5, -38, 83, 13, 5, 13, 5, 13, 5:");
	b.print();
	Pause();
	
	//testing of the infinite recursion avoiding functionality
	Step("Let us test recursion checking for removeAll and addAll.");
	Step("B.addAll(B) should give an error:");
	b.addAll(&b);	
}

void to_array_test()
{
	LinkedList hop;
	int* elements;
	int nb_elements;
	int a;
	
	//intro
	Step("We are going to test the toArray() method which hands out the LinkedList's integers into an array.",0);
	
	//filling some list
	Step("Be a list with integers 1, 17, 8, 5");
	hop.add(1); hop.add(17); hop.add(8); hop.add(5);
	hop.print();
	
	Pause(false);
	//getting the integers from it into an array with the toArray() method & printing those integers ourselves
	Step("Now let's get all those integers ourselves to an int* and print them");
	elements = hop.toArray();
	nb_elements = hop.size();
	for(a=0;a<nb_elements;a++)
	{
		cout << elements[a] << ((a!=nb_elements-1) ? ",":"");
	}
	cout << "."<< endl << "Done printing from the integer array we got." << endl;
}

int main()
{
	MenuItem m1(print_size_isEmpty_add,"print(), int size(), bool isEmpty(), add(int value), add(int index, int value)");
	MenuItem m2(remove_clear,"void remove(int index), void clear()");
	MenuItem m3(contains_get_search,"int get(int index), bool contains(int value), int search(int value)");
	MenuItem m4(add_all_remove_all,"int addAll(Collection*),int addAll(int index,Collection*) and int removeAll(Collection*)");
	MenuItem m5(to_array_test,"int* toArray()");
	
	Menu M("Testing of class LinkedList");
	M.add(m1); M.add(m2); M.add(m3); M.add(m4); M.add(m5);
	M.run();
	//contains_get_search();
	return 0;
}
